package com.cf.spel;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.SpelCompilerMode;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * game-server-SpELService
 *
 * @author <a href="2428922347@qq.com">Zhu mingming</a>
 * @info
 * @since 2018/6/14 上午 10:47
 */
@Slf4j
public class SpELService implements InitializingBean {

    @Autowired
    private ApplicationContext applicationContext;

    private Map<String, Object> objectMap = new HashMap<>();

    private BeanFactoryResolver beanFactoryResolver;

    private SpelParserConfiguration config;

    private SpelExpressionParser spelExpressionParser;


    /**
     * @param method  spel所在的方法
     * @param elValue spel表达式
     * @param type    值的类型
     * @param ars     方法参数
     * @param <T>
     * @return
     */
    public <T> T getSpELValue(Method method, String elValue, Class<T> type, Object[] ars, Object target) {
        log.info("开始调用SpELService 获取【{}】的值", elValue);
        StandardEvaluationContext context = new StandardEvaluationContext();

        //处理方法参数
        if (method != null && ars != null) {
            String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(method);
            for (int i = 0; i < parameterNames.length; i++) {
                context.setVariable(parameterNames[i], ars[i]);
            }
        }

        //注册自己
        if (target != null) {
            context.setVariable("self", target);
        }

        context.setBeanResolver(beanFactoryResolver);
        Expression expr = spelExpressionParser.parseExpression(elValue);
        T value = expr.getValue(context, type);
        log.info("调用SpELService 获取【{}】的值为【{}】", elValue, value);
        return value;
    }

    /**
     * @param method  spel所在的方法
     * @param elValue spel表达式
     * @param type    值的类型
     * @param ars     方法参数
     * @param <T>
     * @return
     */
    public <T> T getSpELValue(Method method, String elValue, Class<T> type, Object[] ars) {
        return getSpELValue(method, elValue, type, ars, null);
    }


    /**
     * @param elValue spel表达式
     * @param type    值的类型
     * @param <T>
     * @return
     */
    public <T> T getSpELValue(String elValue, Class<T> type) {
        return getSpELValue(null, elValue, type, null, null);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.config = new SpelParserConfiguration(SpelCompilerMode.MIXED, this.getClass().getClassLoader(), true, true, 100);
        this.beanFactoryResolver = new BeanFactoryResolver(applicationContext);
        this.spelExpressionParser = new SpelExpressionParser(config);
    }
}
